{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Coding Exercise: Model Adaption Meta Learning\n",
    "\n",
    "In this tutorial, we will implement Model Adaption Meta Learning, to learn a simple curve of sinusoidal data.\n",
    "If you recall Model Agnostic Meta Learning, consists of 2 loops:\n",
    "1. To learn parameters for all tasks.\n",
    "2. To learn task specific parameters\n",
    "\n",
    "MAML algorithm aims to learn such parameters that can adapt to new tasks with very few examples. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"Images/parameters.png\" width=\"600\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "<img src=\"Images/maml_algo.png\" width=\"500\"/>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 1: Import Libraries \n",
    "Let's begin by importing some simple libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import math\n",
    "import random\n",
    "import torch\n",
    "from torch import nn\n",
    "from torch.nn import functional as F\n",
    "import matplotlib as mpl\n",
    "mpl.use('Agg')\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we are choosing p(T) as sinsusoidal curve family. So, as next step, we will create a sinsuoidal data points creater function, which will return data points and labels of it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def generate_dataset(number_of_examples, test=False):\n",
    "    if test:\n",
    "        b = math.pi\n",
    "    else:\n",
    "        b = 0 if random.choice([True, False]) else math.pi # setting up beta variable randomly\n",
    "    x = torch.rand(number_of_examples, 1)*4*math.pi - 2*math.pi # randomly generate x datapoints \n",
    "    y = torch.sin(x + b) # generate labels in form of sine-curve for randomly generated x\n",
    "    return x,y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 2: Create a simple neural network architecture, which is going to learn the sinusoidal curve. \n",
    "As mentioned above, we will be getting randomly generated data of sinusoidal curve so, we will be using a simple 2 layer neural network architecture, and as Loss Function we will use L1 loss, as it's a regression exercise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def NeuralNetwork(x, params):\n",
    "    x = F.linear(x, params[0], params[1])\n",
    "    x = F.relu(x)\n",
    "    x = F.linear(x, params[2], params[3])\n",
    "    x = F.relu(x)\n",
    "    x = F.linear(x, params[4], params[5])\n",
    "    return x\n",
    "\n",
    "# define Initial Parameters\n",
    "theta = [\n",
    "    torch.Tensor(32, 1).uniform_(-1., 1.).requires_grad_(),\n",
    "    torch.Tensor(32).zero_().requires_grad_(),\n",
    "\n",
    "    torch.Tensor(32, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),\n",
    "    torch.Tensor(32).zero_().requires_grad_(),\n",
    "\n",
    "    torch.Tensor(1, 32).uniform_(-1./math.sqrt(32), 1./math.sqrt(32)).requires_grad_(),\n",
    "    torch.Tensor(1).zero_().requires_grad_(),\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### step 3: set up parameters for training \n",
    "We will be using Stochastic Gradient Descent Optimization Method, and training model using just 5 examples per task.\n",
    "We can also set it to 1, to make it one-shot learning. \n",
    "Here, alpha and beta is a hyper-parameter, can be seen as learning rate. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "alpha, beta = 3e-2, 1e-2 # hyper-paramaters as shown in algorithm above.\n",
    "opt = torch.optim.SGD(theta, lr=beta) # Optimizer\n",
    "number_of_examples= 5 # 5-shot learning, 5 examples per task.\n",
    "iterations = 100000 # number of iterations to enable the model to reach optimal point\n",
    "epochs = 4 # number of iterations to train task specific model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 4:  Implement Optimization Algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iteration 0 Loss 0.7769\n",
      "Iteration 1000 Loss 0.8167\n",
      "Iteration 2000 Loss 0.3264\n",
      "Iteration 3000 Loss 0.6297\n",
      "Iteration 4000 Loss 0.7330\n",
      "Iteration 5000 Loss 0.5633\n",
      "Iteration 6000 Loss 0.6545\n",
      "Iteration 7000 Loss 0.7192\n",
      "Iteration 8000 Loss 0.3932\n",
      "Iteration 9000 Loss 0.8063\n",
      "Iteration 10000 Loss 0.6289\n",
      "Iteration 11000 Loss 0.6174\n",
      "Iteration 12000 Loss 0.7092\n",
      "Iteration 13000 Loss 0.6059\n",
      "Iteration 14000 Loss 0.7731\n",
      "Iteration 15000 Loss 0.4221\n",
      "Iteration 16000 Loss 0.5452\n",
      "Iteration 17000 Loss 0.3352\n",
      "Iteration 18000 Loss 0.3369\n",
      "Iteration 19000 Loss 0.6712\n",
      "Iteration 20000 Loss 0.4838\n",
      "Iteration 21000 Loss 0.4788\n",
      "Iteration 22000 Loss 0.4932\n",
      "Iteration 23000 Loss 0.9714\n",
      "Iteration 24000 Loss 0.3798\n",
      "Iteration 25000 Loss 0.2735\n",
      "Iteration 26000 Loss 0.1745\n",
      "Iteration 27000 Loss 0.1496\n",
      "Iteration 28000 Loss 0.5535\n",
      "Iteration 29000 Loss 0.2386\n",
      "Iteration 30000 Loss 0.2878\n",
      "Iteration 31000 Loss 0.4920\n",
      "Iteration 32000 Loss 0.2879\n",
      "Iteration 33000 Loss 0.1564\n",
      "Iteration 34000 Loss 0.4612\n",
      "Iteration 35000 Loss 0.0270\n",
      "Iteration 36000 Loss 0.1737\n",
      "Iteration 37000 Loss 0.0552\n",
      "Iteration 38000 Loss 0.2631\n",
      "Iteration 39000 Loss 0.1117\n",
      "Iteration 40000 Loss 0.0784\n",
      "Iteration 41000 Loss 0.3187\n",
      "Iteration 42000 Loss 0.2018\n",
      "Iteration 43000 Loss 0.0920\n",
      "Iteration 44000 Loss 0.1686\n",
      "Iteration 45000 Loss 0.0830\n",
      "Iteration 46000 Loss 0.1739\n",
      "Iteration 47000 Loss 0.1474\n",
      "Iteration 48000 Loss 0.1199\n",
      "Iteration 49000 Loss 0.2148\n",
      "Iteration 50000 Loss 0.1277\n",
      "Iteration 51000 Loss 0.0893\n",
      "Iteration 52000 Loss 0.1742\n",
      "Iteration 53000 Loss 0.1999\n",
      "Iteration 54000 Loss 0.1891\n",
      "Iteration 55000 Loss 0.1029\n",
      "Iteration 56000 Loss 0.0731\n",
      "Iteration 57000 Loss 0.1106\n",
      "Iteration 58000 Loss 0.1105\n",
      "Iteration 59000 Loss 0.0413\n",
      "Iteration 60000 Loss 0.1894\n",
      "Iteration 61000 Loss 0.0368\n",
      "Iteration 62000 Loss 0.0923\n",
      "Iteration 63000 Loss 0.0545\n",
      "Iteration 64000 Loss 0.1668\n",
      "Iteration 65000 Loss 0.0228\n",
      "Iteration 66000 Loss 0.1297\n",
      "Iteration 67000 Loss 0.1295\n",
      "Iteration 68000 Loss 0.0971\n",
      "Iteration 69000 Loss 0.1857\n",
      "Iteration 70000 Loss 0.0658\n",
      "Iteration 71000 Loss 0.1020\n",
      "Iteration 72000 Loss 0.1177\n",
      "Iteration 73000 Loss 0.0387\n",
      "Iteration 74000 Loss 0.1645\n",
      "Iteration 75000 Loss 0.1069\n",
      "Iteration 76000 Loss 0.1780\n",
      "Iteration 77000 Loss 0.0778\n",
      "Iteration 78000 Loss 0.0665\n",
      "Iteration 79000 Loss 0.1508\n",
      "Iteration 80000 Loss 0.0592\n",
      "Iteration 81000 Loss 0.0669\n",
      "Iteration 82000 Loss 1.1948\n",
      "Iteration 83000 Loss 0.0448\n",
      "Iteration 84000 Loss 0.0564\n",
      "Iteration 85000 Loss 0.2221\n",
      "Iteration 86000 Loss 0.0204\n",
      "Iteration 87000 Loss 0.0956\n",
      "Iteration 88000 Loss 0.0465\n",
      "Iteration 89000 Loss 0.1674\n",
      "Iteration 90000 Loss 0.1361\n",
      "Iteration 91000 Loss 0.0409\n",
      "Iteration 92000 Loss 0.0682\n",
      "Iteration 93000 Loss 0.0397\n",
      "Iteration 94000 Loss 0.0491\n",
      "Iteration 95000 Loss 0.0578\n",
      "Iteration 96000 Loss 0.1249\n",
      "Iteration 97000 Loss 0.2885\n",
      "Iteration 98000 Loss 0.1075\n",
      "Iteration 99000 Loss 0.0787\n"
     ]
    }
   ],
   "source": [
    "for it in range(iterations): # training for 1 million iterations\n",
    "    b = 0 if random.choice([True, False]) else math.pi # setting up beta variable randomly\n",
    "    \n",
    "    #### Randomly obtain task 1 sinusoidal data ####\n",
    "    x = torch.rand(4, 1)*4*math.pi - 2*math.pi\n",
    "    y = torch.sin(x + b)\n",
    "    \n",
    "    #### Randomly obtain the task 2 sinusoidal data ####\n",
    "    v_x = torch.rand(4, 1)*4*math.pi - 2*math.pi\n",
    "    v_y = torch.sin(v_x + b)\n",
    "\n",
    "    opt.zero_grad() # setup optimizer\n",
    "\n",
    "    new_params = theta # initialize weights for inner loop\n",
    "    for k in range(4):\n",
    "        f = NeuralNetwork(x, new_params) # re-initialize task 2 neural network with new parameters\n",
    "        loss = F.l1_loss(f, y) # set loss as L1 Loss\n",
    "\n",
    "        # create_graph=True because computing grads here is part of the forward pass.\n",
    "        # We want to differentiate through the SGD update steps and get higher order\n",
    "        # derivatives in the backward pass.\n",
    "        grads = torch.autograd.grad(loss, new_params, create_graph=True)\n",
    "        new_params = [(new_params[i] - alpha*grads[i]) for i in range(len(theta))] # update weights of inner loop\n",
    "\n",
    "    v_f = NeuralNetwork(v_x, new_params) # re-initialize task 1 neural network with new parameters\n",
    "    loss2 = F.l1_loss(v_f, v_y) # calculate Loss\n",
    "    loss2.backward() # Backward Pass\n",
    "\n",
    "    opt.step()\n",
    "\n",
    "    if it % 1000 == 0: \n",
    "        print ('Iteration %d Loss %.4f' % (it, loss2))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 5: Test Model\n",
    "Once we have obtained right parameters:\n",
    "1. sample task specific 5 data points.\n",
    "2. train model with only 5 points and obatin task specific parameters(test_theta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Randomly generate 5 data points.\n",
    "t_b = math.pi \n",
    "t_x = torch.rand(4, 1)*4*math.pi - 2*math.pi\n",
    "t_y = torch.sin(t_x + t_b)\n",
    "\n",
    "opt.zero_grad()\n",
    "n_inner_loop = 5\n",
    "t_params = theta\n",
    "for k in range(n_inner_loop):\n",
    "    t_f = NeuralNetwork(t_x, t_params)\n",
    "    t_loss = F.l1_loss(t_f, t_y)\n",
    "\n",
    "    grads = torch.autograd.grad(t_loss, t_params, create_graph=True)\n",
    "    t_params = [(t_params[i] - alpha*grads[i]) for i in range(len(theta))]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Plot the output\n",
    "Now, we will obtain certain sine curve points for plotting purpose, and observe our trained model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "test_x = torch.arange(-2*math.pi, 2*math.pi, step=0.01).unsqueeze(1)\n",
    "test_y = torch.sin(test_x + t_b)\n",
    "\n",
    "test_f = NeuralNetwork(test_x, t_params)\n",
    "\n",
    "plt.plot(test_x.data.numpy(), test_y.data.numpy(), label='sin(x)')\n",
    "plt.plot(test_x.data.numpy(), test_f.data.numpy(), label='net(x)')\n",
    "plt.plot(t_x.data.numpy(), t_y.data.numpy(), 'o', label='Examples')\n",
    "plt.legend()\n",
    "plt.savefig('maml-sine.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
